DockerでローカルにIceberg + Spark環境を構築し、DBeaverで接続してみた

DockerでローカルにIceberg + Spark環境を構築し、DBeaverで接続してみた

Clock Icon2024.12.18

データアナリティクス事業本部のueharaです。

今回は、DockerでローカルにIceberg + Spark環境を構築し、DBeaverで接続してみたいと思います。

はじめに

re:Invent 2024でフルマネージドなApache Iceberg tablesであるといえる S3 Tables が発表されるなど、大量のデータを効率よく扱うためのオープンソースのテーブルフォーマットであるIcebergがより勢いづいている印象を受けます。

AWS上ではIcebergを扱うためにS3 + Athenaという構成が取れたりするのですが、今回は手軽に試すためにローカル環境で構築してみたいと思います。

(簡単に)Icebergについて

Icebergはあくまで「Table Spec」の1つになります。

20241218_ice_01
引用元

すなわち、「データへの効率的なアクセスをするためにこういう風にデータファイルを管理します」という枠組みであり、Icebergそのものがコンピューティング能力やストレージ機能を有しているといったものではありません。

実際にIcebergテーブルを扱うのはSparkやTrinoといったクエリエンジンになります。

補足ですが、Icebergのアーキテクチャは以下のようになっています。

20241218_ice_07

環境構築

docker-compose.ymlの作成

公開されているIceberg + SparkのDockerイメージはいくつかありますが、今回は公式でもサンプルとして利用されているtabulario/spark-icebergのものを利用します。

公式サンプルではストレージとしてMinIO(S3互換のオブジェクトストレージ)を利用しているようで、これもそのまま使わせてもらいます。

作成したdocker-compose.ymlは以下の通りです。

docker-compose.yml
version: "3"

services:
  spark-iceberg:
    image: tabulario/spark-iceberg
    container_name: spark-iceberg
    build: spark/
    networks:
      iceberg_net:
    depends_on:
      - rest
      - minio
    volumes:
      - ./warehouse:/home/iceberg/warehouse
      - ./notebooks:/home/iceberg/notebooks/notebooks
    environment:
      - AWS_ACCESS_KEY_ID=admin
      - AWS_SECRET_ACCESS_KEY=password
      - AWS_REGION=us-east-1
    ports:
      - 8888:8888
      - 8080:8080
      - 10000:10000
      - 10001:10001
  rest:
    image: apache/iceberg-rest-fixture
    container_name: iceberg-rest
    networks:
      iceberg_net:
    ports:
      - 8181:8181
    environment:
      - AWS_ACCESS_KEY_ID=admin
      - AWS_SECRET_ACCESS_KEY=password
      - AWS_REGION=us-east-1
      - CATALOG_WAREHOUSE=s3://warehouse/
      - CATALOG_IO__IMPL=org.apache.iceberg.aws.s3.S3FileIO
      - CATALOG_S3_ENDPOINT=http://minio:9000
  minio:
    image: minio/minio
    container_name: minio
    volumes:
      - ./data:/data
    environment:
      - MINIO_ROOT_USER=admin
      - MINIO_ROOT_PASSWORD=password
      - MINIO_DOMAIN=minio
    networks:
      iceberg_net:
        aliases:
          - warehouse.minio
    ports:
      - 9001:9001
      - 9000:9000
    command: ["server", "/data", "--console-address", ":9001"]
  mc:
    depends_on:
      - minio
    image: minio/mc
    container_name: mc
    networks:
      iceberg_net:
    environment:
      - AWS_ACCESS_KEY_ID=admin
      - AWS_SECRET_ACCESS_KEY=password
      - AWS_REGION=us-east-1
    entrypoint: >
      /bin/sh -c "
      until (/usr/bin/mc config host add minio http://minio:9000 admin password) do echo '...waiting...' && sleep 1; done;
      /usr/bin/mc rm -r --force minio/warehouse;
      /usr/bin/mc mb minio/warehouse;
      /usr/bin/mc policy set public minio/warehouse;
      tail -f /dev/null
      "
networks:
  iceberg_net:

マウント用ディレクトリの作成

docker-compose.ymlの作成が完了したら、同じ階層にdata, notebooks, warehouse というディレクトリを作成し、アクセス権限の設定をしておきます。

$ mkdir data notebooks warehouse

$ chmod 755 data notebooks warehouse

この段階で、ディレクトリ構成は以下のようになっていると思います。

.
├── data
├── docker-compose.yml
├── notebooks
└── warehouse

Dockerコンテナの起動とデータベースの作成

Dockerコンテナの起動は以下のコマンドで実行可能です。

$ docker-compose up

各サービスの立ち上げが完了したら、以下コマンドでSparkのセッションを開始します。

$ docker exec -it spark-iceberg spark-sql

セッションが開始されたら default というデータベースを作成しておきます。

spark-sql ()> CREATE DATABASE IF NOT EXISTS default;

これで一旦準備は完了です。

DBeaverでアクセス

接続設定

DBeaverを開き、「新しい接続の作成」を行います。接続タイプは「Apache Hive 4+」を選択します。

20241218_ice_02

ドライバのダウンロードがされていなければ以下の通り「ドライバの設定」の画面が立ちあがるので、ダウンロードしておきます。

20241218_ice_03

データベースは先に作成した「default」を指定します。ユーザ名とパスワードは空欄で問題ありません。

20241218_ice_04

左下の「テスト接続」ボタンを押して接続が成功すれば接続設定は完了です。

20241218_ice_05

クエリの実行

DBeaverで接続ができたら、適当にテーブルを作成しデータを挿入してみます。

DBeaverで実行
-- テーブルの作成
CREATE TABLE default.test_table
(
  location_id STRING,
  user_id INT,
  name STRING
)
USING iceberg
PARTITIONED BY (location_id);

-- データの挿入
INSERT INTO default.test_table 
VALUES ('aaa-111', 1, 'Alice'), ('bbb-222', 2, 'Bob');

パーティションを確認したいので、テーブル作成時にlocation_idというカラムをパーティションに指定しています。

データの挿入が完了したら、SELECTクエリでデータが取得できるか確認します。

DBeaverで実行
SELECT *
FROM default.test_table

取得できました!

20241218_ice_06

ファイルの確認

ここまで完了したら、MinIOにマウントしている data フォルダを確認します。

$ tree data
data
└── warehouse
    └── default
        └── test_table
            ├── data
            │   ├── location_id=aaa-111
            │   │   └── 00000-9-e6eca642-bf54-4c83-ba93-a5737dcfe3fd-0-00001.parquet
            │   │       └── xl.meta
            │   └── location_id=bbb-222
            │       └── 00000-9-e6eca642-bf54-4c83-ba93-a5737dcfe3fd-0-00002.parquet
            │           └── xl.meta
            └── metadata
                ├── 00000-d68c1a54-03f8-4caa-a26a-ed2e44c16a79.metadata.json
                │   └── xl.meta
                ├── 00001-f38636ef-3f70-47ee-af49-cbef2c84cac4.metadata.json
                │   └── xl.meta
                ├── 07de197b-736c-46b9-8e32-748d558cafb8-m0.avro
                │   └── xl.meta
                └── snap-6608030360858061675-1-07de197b-736c-46b9-8e32-748d558cafb8.avro
                    └── xl.meta

パーティションに設定した location_id で区切られているデータファイル(.parquet)や、各種メタデータファイルが確認できると思います。

MinIOの構造により .parquet ファイルをローカルから直接参照することはできないので、以下のようにしてファイルをローカルに持ってきて確認してみます。

# まずコンテナ内の一時ディレクトリにコピー
$ docker exec -it mc mc cp minio/warehouse/default/test_table/data/location_id=aaa-111/00000-9-e6eca642-bf54-4c83-ba93-a5737dcfe3fd-0-00001.parquet /tmp/

# そのファイルをホストにコピー
docker cp mc:/tmp/00000-9-e6eca642-bf54-4c83-ba93-a5737dcfe3fd-0-00001.parquet ./

コピーされたファイルを適当なParquetビューワーで確認すると、以下の通りデータが確認できます。

20241218_ice_08

最後に

今回は、DockerでローカルにIceberg + Spark環境を構築し、DBeaverで接続してみました。

参考になりましたら幸いです。

参考文献

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.